﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Threading;

namespace IQIGame.Onigao.Framework
{
    public class BetterLinkedList<T>
    {
        private BetterLinkedListNode<T> head;
        private BetterLinkedListNode<T> tail;
        
        public T First => head.value;
        public T Last => tail.value;
        
        public BetterLinkedListNode<T> FirstNode => head;
        public BetterLinkedListNode<T> LastNode => tail;
        
        public int Count { get; private set; }

        public BetterLinkedListNode<T> AddAfter(BetterLinkedListNode<T> node, T value)
        {
            if (node == null)
            {
                return this.AddFirst(value);
            }
            var newNode = ClassPool.Get<BetterLinkedListNode<T>>();
            newNode.value = value;
            newNode.prev = node;
            newNode.next = node.next;
            if (node.next != null)
            {
                node.next.prev = newNode;
            }
            else
            {
                tail = newNode;
            }
            node.next = newNode;
            Count++;
            return newNode;
        }
        
        public BetterLinkedListNode<T> AddBefore(BetterLinkedListNode<T> node, T value)
        {
            if (node == null)
            {
                return this.AddLast(value);
            }
            var newNode = ClassPool.Get<BetterLinkedListNode<T>>();
            newNode.value = value;
            newNode.prev = node.prev;
            newNode.next = node;
            if (node.prev != null)
            {
                node.prev.next = newNode;
            }
            else
            {
                head = newNode;
            }
            node.prev = newNode;
            Count++;
            return newNode;
        }
        
        public BetterLinkedListNode<T> AddFirst(T value)
        {
            var node = ClassPool.Get<BetterLinkedListNode<T>>();
            node.value = value;
            if (head == null)
            {
                head = node;
                tail = node;
            }
            else
            {
                head.prev = node;
                node.next = head;
                head = node;
            }
            Count++;
            return node;
        }
        
        public BetterLinkedListNode<T> AddLast(T value)
        {
            var node = ClassPool.Get<BetterLinkedListNode<T>>();
            node.value = value;
            if (head == null)
            {
                head = node;
                tail = node;
            }
            else
            {
                tail.next = node;
                node.prev = tail;
                tail = node;
            }
            Count++;
            return node;
        }
        
        public void RemoveNode(BetterLinkedListNode<T> node)
        {
            if (node.prev != null)
            {
                node.prev.next = node.next;
            }
            else
            {
                head = node.next;
            }
            if (node.next != null)
            {
                node.next.prev = node.prev;
            }
            else
            {
                tail = node.prev;
            }
            ClassPool.Put(node);
            Count--;
        }
        
        public bool Remove(T value)
        {
            BetterLinkedListNode<T> linkedListNode = Find(value);
            if (linkedListNode != null)
            {
                RemoveNode(linkedListNode);
                return true;
            }
            return false;
        }
        
        public BetterLinkedListNode<T> Find(T value)
        {
            BetterLinkedListNode<T> next = head;
            EqualityComparer<T> @default = EqualityComparer<T>.Default;
            do
            {
                if (@default.Equals(next.value, value))
                {
                    return next;
                }

                next = next.next;
            } while (next != null);
            
            return null;
        }

        public void RemoveAllAfter(BetterLinkedListNode<T> node)
        {
            if (node == null)
            {
                return;
            }

            for (; node.next != null;)
            {
                this.RemoveNode(node.next);
            }
        }

        public void Clear()
        {
            BetterLinkedListNode<T> next = head;
            while (next != null)
            {
                BetterLinkedListNode<T> linkedListNode = next;
                next = next.next;
                
                ClassPool.Put(linkedListNode);
            }
            head = null;
            this.Count = 0;
        }
    }
    
    public class BetterLinkedListNode<T> : IReusableClass
    {
        public T value;
        
        public BetterLinkedListNode<T> prev;
        public BetterLinkedListNode<T> next;
        
        public uint MaxStore => 5;
        public void OnReset()
        {
            value = default;
            prev = null;
            next = null;
        }
    }
}